#include "InterpretadorMepa.h"

InterpretadorMepa::InterpretadorMepa(vector<LinhaMepa> & mVetor,vector<string>& mParametros)
{
	// pega as instrucoes passadas na main
	for(int i = 1; i< mParametros.size(); i++)
	{
		//string sem o hifen inicial
		char escolha = mParametros.at(i)[1];
		
		switch(escolha)
		{
			//-D n] [-P n] [-M n] [-I] [-?] [-R arq] arquivo.mep
			case 'D': RegBase(mParametros.at(++i));
						break;
			case 'P': P(mParametros.at(++i));
						break;
			case 'M': M(mParametros.at(++i));
					    break;
			case 'I': I();
						break;
			case '?': help();
					    break;	
			case 'R': R(mParametros.at(++i));
						break;
			default : this->mArquivoMEPA = mParametros.at(i);
						break;

		}

	}
	this->mMepa = mVetor; // recebe o vetor com as linhas do arquivo da MEPA
	this->mI = 0;
	this->mS = -1;
	
}
void InterpretadorMepa::E()
{

	this->mM = new string[100];
	this->mD = new  int[100];
	this->mP = new string[100];
}
void InterpretadorMepa::R(string mArquivo)
{
	this->mMOSM = mArquivo;
	
}

void InterpretadorMepa::help()
	{
	cout<<"\n\n		Interpretador\n"
	<<"	mepa [-J] [-D n] [-P n] [-M n] [-I] [-?] [-R arq] arquivo.mep\n"
	<<"	-J: [implementação opcional] Abre janela e mostra execução do programa. Sugestão: execução passo-a-passo, mostrar registradores. Pensar a respeito: Como você faria um depurador para o seu programa Pascal usando MEPA?\n"
	<<"	-D n: número (n) de registradores de base.\n"
	<<"	-P n: tamanho (n), em palavras (16 bits), da memória de programa.\n"
	<<"	-M n: tamanho (n), em palavras (16 bits),  da memória de dados.\n"
	<<"	-I:  mostra na saída padrão a identificação da equipe.\n"
	<<"	-?: (ajuda) mostra os parâmetros do interpretador.\n"
	<<"	-R arq: arquivo em que é colocado o resultado da execução da instrução MOSM. Se esta opção não for usada, o resultado é mostrado na saída padrão. Atenção: o formato do relatório é rígido.\n"
	<<"	arquivo.mep: arquivo executável, contendo instruções MEPA\n"
	<<"	mensagens de erro (arquivo não encontrado, instrução inexistente, etc) devem ser mostradas na saída padrão.\n";
}
void InterpretadorMepa::RegBase(string mValor)
{
	stringstream n(mValor);
	int result;
	n>>result;
	mTD = result;
	this->mD = new  int[result];
	
}
void InterpretadorMepa::P(string mValor)
{
	stringstream n(mValor);
	int result;
	n>>result;
	mTP = result;
	this->mP = new string[result];
	
}
void InterpretadorMepa::M(string mValor)
{
	stringstream n(mValor);
	int result;
	n>>result;
	mTM = result;
	this->mM = new string[result];
	
}
void InterpretadorMepa::I()
{
	cout<<"***************************************\n"
		<<"Equipe: FODA(Fabricio O Dador Assumido)\n"
		<<"Integrantes:                           \n"
		<<"	Fabricio Ferracioli           \n"
		<<"	Renan Barbosa Campos          \n"
		<<"***************************************\n";
		
}

 
void InterpretadorMepa::ExecutaMepa()
{
	

	
	do
	{
		this->mCorrent = this->mMepa.at(this->mI);
		
			if(this->mCorrent.GetmLinha() == "ARMZ")
			{	ARMZ();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "DSVS")
			{	DSVS();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "DSVF")
			{	DSVF();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "NADA")
			{	NADA();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "IMPR")
			{	IMPR();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "IMPL")
			{	IMPL();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "IMPC")
			{	IMPC();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "INPP")
			{	
				INPP();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "AMEM")
			{	AMEM();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "PARA")
			{	PARA();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "LEIT")
			{	LEIT();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CHPR")
			{	CHPR();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "ENPR")
			{	ENPR();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "RTPR")
			{	RTPR();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "DMEM")
			{	DMEM();
				continue;
			}
			//====================================
			if(this->mCorrent.GetmLinha() == "CRVL")
			{	CRVL();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CRCT")
			{	CRCT();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "SUBT")
			{	SUBT();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "MULT")
			{	MULT();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "DIVI")
			{	DIVI();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "INVR")
			{	INVR();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CONJ")
			{	CONJ();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "DISJ")
			{	DISJ();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "NEGA")
			{	NEGA();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMME")
			{	CMME();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMMA")
			{	CMMA();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMIG")
			{	CMIG();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMDG")
			{	CMDG();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMEG")
			{	CMEG();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CMAG")
			{	CMAG();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "SOMA")
			{	SOMA();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CRVI")
			{	CRVI();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "ARMI")
			{	ARMI();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "CREN")
			{
				CREN();
				continue;
			}
			if(this->mCorrent.GetmLinha() == "MOSM")
			{
				MOSM();
				continue;
			}
	}while( this->mCorrent.GetmLinha() != "PARA"); 
	
}

void InterpretadorMepa::ARMI()
{
	/*(armazenar valor)
	M[ M[D[k]+n] ] := M[s];  s := s – 1*/
	
	
	int k = this->mCorrent.getmParamentro(0);
	int n = this->mCorrent.getmParamentro(1);

	stringstream o( mM[mD[k] + n] );
	int result;
	//resebe o valor e transforma pra inteiro
	o>>result;
	mM[result] = mM[mS];
	mS--;
	mI++;
	
	
	
}

void InterpretadorMepa::INVR()
{
	//(inverter sinal)
	//M[s] := -M[s]
	stringstream aux1;
	stringstream aux2;
	//recebe o valor inteiro
	aux1<<this->mM[this->mS];
	int inverte;
	// joga valor para um auxiliar
	aux1>>inverte;
	
	inverte = (-1)*inverte;
	aux2<<inverte;
	
	//recebe o valor de b invertido
	this->mM[this->mS] = aux2.str();
	
	this->mI++;
	
}

void InterpretadorMepa::CHPR()
{
	//(chamar procedimento)
	//s:= s + 1; M[s]:= i +1 (*retorno*); I:= "endereco de l
	this->mS++;
	stringstream aux1;
	
	// recebe valor para atribuir a m[s]
	int I = this->mI+1;
	
	// converte para string
	aux1<<I;
	
	// atribui para mM[this->mS]
	aux1>>this->mM[this->mS];
	this->mI = this->mCorrent.getmParamentro(0);
	
}
void InterpretadorMepa::ENPR()
{
	//(entrar procedimento 
	//s := s +1; M[s] := D[k]; D[k] := s +1
	stringstream aux1;
	int k = this->mCorrent.getmParamentro(0);
	this->mS++;
	aux1<<this->mD[k];
	aux1>>this->mM[this->mS];
	
	this->mD[k] = this->mS+1;
	this->mI++;
}
void InterpretadorMepa::RTPR()
{
	//(retornar do procedimento – k: nível léxico)
	//D[k] := M[s];  i := M[s-1];  s := s � (n+2)
	int k = this->mCorrent.getmParamentro(0);
	stringstream o(this->mM[this->mS]);
	int j ;
	o >> j;
	this->mD[k] = j;
	
	stringstream I(this->mM[this->mS - 1]);
	I>>this->mI;
	
	this->mS = this->mS -(this->mCorrent.getmParamentro(1)+2);
}

void InterpretadorMepa::CRVI()
{
	
	/*(carregar valor indireto)
	s := s + 1;  M[s] := M[ M[D[k] + n] ]*/
	
	mS++;
	int k = this->mCorrent.getmParamentro(0);
	int n = this->mCorrent.getmParamentro(1);
	stringstream o( mM[mD[k] + n] );
	int result;
	//resebe o valor e transforma pra inteiro
	o>>result;
	mM[mS] = mM[result];
	mI++;
	
	
}

void InterpretadorMepa::DMEM()
{
	//(desalocar memória)
	//s := s - n
	this->mS = mS - this->mCorrent.getmParamentro(0);
	this->mI++;
}


void InterpretadorMepa::ARMZ()
{
	/*  ARMZ k,n
	 *  (armazenar valor)
     *  M[D[k]+n] := M[s];  s := 
	 */
	 
	int k = this->mCorrent.getmParamentro(0); // retorna valor de n'
	int n = this->mCorrent.getmParamentro(1); // retorna valor de k'
	this->mM[this->mD[k]+n]  = this->mM[this->mS];
	cout<<this->mM[this->mD[k]+n]<<endl;
	this->mS = this->mS - 1;
	this->mI++;
	
}

void InterpretadorMepa::DSVS()
{
	/* DSVS p
	 * (desviar sempre)
	 *i := p
	 */
	 // retorna o parametro da linha com instrucao DSVS
	 this->mI = this->mCorrent.getmParamentro(0);
	
}

void InterpretadorMepa::DSVF()
{
	/*
	 * DSVF p (desviar se falso)
	 * se M[s] = 0 ent�o i:= p sen�o i := i + 1; s:= s -1
	 */
	
	int compara;
	stringstream aux1;
	aux1<<this->mM[this->mS];
	aux1>>compara;
	
	if( compara == 0 )
	{
		this->mI = this->mCorrent.getmParamentro(0);
	}else
	{
		this->mI = this->mI + 1;
	}
	this->mS = this->mS - 1 ;
}

void InterpretadorMepa::NADA()
{
	/*
	 * 
	 * NADA
	 */
	 this->mI++;
}

void InterpretadorMepa::LEIT()
{
	/*
	 * LEIT (leitura)
	   s := s + 1;   M[s] := {pr�ximo valor da entrada}
	 * 
	 */
	 this->mS = this->mS + 1;
	 // ver  o significado
	 //this->mM.at(this->mS) = 
	 this->mI++;
}

void InterpretadorMepa::IMPR()
{
      /*
       * 
       * (imprimir)
		{Imprima M[s]};   s := s -1
		*/
	cout<<this->mM[this->mS];
	this->mS--;
	this->mI++;

}
void InterpretadorMepa::IMPL()
{
	/*
	 * 
	 * (imprimir e pular linha)
		{Imprima M[s], inicie nova linha}; s := s - 1
	*/
	cout<<this->mM[this->mS]<<endl;
	this->mS--;
	this->mI++;
}
void InterpretadorMepa::IMPC()
{
	/*
	 * (imprimir caractere)
     {Imprima ASC(M[s]), inicie nova linha}; s := s - 1
     */
     cout<<this->mM[this->mS]<<endl;
	this->mS--;
	this->mI++;
}
void InterpretadorMepa::INPP()
{
	/*
	 * (iniciar programa principal)
		s := -1
     */
     this->mI++;
     mD[0] = 0;
}

void InterpretadorMepa::AMEM()
{
	/*(alocar mem�ria)
	* s := s + m
	*/
	
	
	this->mS = this->mS + this->mCorrent.getmParamentro(0);
	this->mI++;
}

void InterpretadorMepa:: PARA()
{
	/*
	 * (p�ra a execu��o da MEPA)
	 * 
	 */
}


void InterpretadorMepa::CRCT()
{
	//string comando = this->mMepa[mI].pop_back();
	this->mS++;
	stringstream aux1;
	aux1<<this->mCorrent.getmParamentro(0);
	aux1>>this->mM[this->mS];
	this->mI++;
}

void InterpretadorMepa::CRVL()
{
	//CRVL k,n
	//(carregar valor)
	//s := s + 1;  M[s] := M[D[k] + n]
	
	this->mS++;
	int k = this->mCorrent.getmParamentro(0);
	int n = this->mCorrent.getmParamentro(1);
	
	this->mM[mS] = this->mM[this->mD[k]+n];
	this->mI++;
}

void InterpretadorMepa::SOMA()
{
	int a, b;
	
	// string para converter
	stringstream soma1(this->mM[this->mS - 1]);
	stringstream soma2(this->mM[this->mS]);
	ostringstream result;
	soma1 >> a;
	soma2 >> b;
	a = a + b;
	result << a;
	this->mM[this->mS - 1] = result.str();
	
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::SUBT()
{
	int a, b;
	// string para converter
	stringstream soma1(this->mM[this->mS - 1]);
	stringstream soma2(this->mM[this->mS]);
	ostringstream result;
	soma1 >> a;
	soma2 >> b;
	a = a - b;
	result << a;
	this->mM[this->mS - 1] = result.str();
	
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::MULT()
{
	int a, b;
	// string para converter
	stringstream soma1(this->mM[this->mS - 1]);
	stringstream soma2(this->mM[this->mS]);
	ostringstream result;
	soma1 >> a;
	soma2 >> b;
	a = a * b;
	result << a;
	this->mM[this->mS - 1] = result.str();
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::DIVI()
{
	int a, b;
	// string para converter
	stringstream soma1(this->mM[this->mS - 1]);
	stringstream soma2(this->mM[this->mS]);
	ostringstream result;
	soma1 >> a;
	soma2 >> b;
	a = a/b;
	result << a;
	this->mM[this->mS - 1] = result.str();
	
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CONJ()
{
	if(this->mM[this->mS - 1].data() == "1" && this->mM[this->mS].data() == "1")
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::DISJ()
{
	if(this->mM[this->mS - 1].data() == "1" || this->mM[this->mS].data() == "1")
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::NEGA()
{
	int a;
	stringstream valor(this->mM[this->mS]);
	ostringstream result;
	valor >> a;
	a = 1 - a;
	result << 1 - a;
	this->mM[this->mS] = result.str();
}

void InterpretadorMepa::CMME()
{
	if(this->mM[this->mS - 1] < this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CMMA()
{
	if(this->mM[this->mS - 1] > this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CMIG()
{

	
	
	if(this->mM[this->mS - 1] == this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CMDG()
{
	if(this->mM[this->mS - 1] != this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CMEG()
{
	if(this->mM[this->mS - 1] <= this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}

void InterpretadorMepa::CMAG()
{
	if(this->mM[this->mS - 1] >= this->mM[this->mS])
		this->mM[this->mS - 1] = "1";
	else
		this->mM[this->mS - 1] = "0";
	this->mS--;
	this->mI++;
}


void InterpretadorMepa::CREN()
{
	/*(carregar endereço)
	s:= s + 1; M[s]:= D[k] + n*/
	int k = this->mCorrent.getmParamentro(0);
	int n = this->mCorrent.getmParamentro(1);
	this->mS++;
	this->mM[this->mS] = this->mD[k] + n;
	this->mI++;
}

void InterpretadorMepa::MOSM()
{
	/* Mostrar Memoria */
	Arquivo arq;

	if(this->mMOSM.size() <= 0)
	{
		cout.fill('0');
		cout << "DUMP DE MEMORIA: "<< this->mArquivoMEPA << endl;
		cout << "-----------------------------" << endl;
		cout << "i: ";
		cout.width(5);
		cout << this->mI;
		cout << endl;
		cout << "s: ";
		cout.width(5);
		cout << this->mS;
		cout << endl;
	}
	else
	{
		arq.ImprimeMosmCabecalho(this->mMOSM.data());
		arq.ImprimeMosmIS(this->mMOSM.data(), this->mI, this->mS);
	}

	
	for(int cont = 0; cont < this->mTD; cont++)
	{
		if(this->mMOSM.size() <= 0)
		{
			cout << "D["<< cont <<"]: ";
			cout.width(5);
			cout << this->mD[cont] << endl;
		}
		else
		{
			arq.ImprimeMosmD(this->mMOSM.data(), cont, this->mD[cont]);
		}
	}
	if(this->mMOSM.size() <= 0)
		cout << "---------------" << endl;
	else
		arq.ImprimeMosmLinha(this->mMOSM.data(), 15);
		
	for(int cont = 0; cont < this->mTM; cont++)
	{
		if(this->mMOSM.size() <= 0)
		{
			cout << "[";
			cout.width(5);
			cout << cont;
			cout << "] " << this->mM[cont] << endl;
		}
		else
		{
			arq.ImprimeMosmM(this->mMOSM.data(), cont, this->mM[cont]);
		}
	}
	if(this->mMOSM.size() <= 0)
		cout << "-----------------------------" << endl;
	else
		arq.ImprimeMosmLinha(this->mMOSM.data(), 35);
	
	this->mI++;
}

InterpretadorMepa::~InterpretadorMepa()
{
}
